import Utils from "./Utils";

class Snake {
    private head: HTMLElement;
    private body: HTMLCollection;
    private element: HTMLElement;

    constructor() {
        this.element = document.getElementById("snake")!;
        this.head = document.querySelector('#snake > div')!;
        this.body = this.element.getElementsByTagName('div');
    }

    get x() {
        return this.head.offsetLeft;
    }

    set x(value) {
        // 如果新值和旧值相同，则直接返回不再修改
        if (this.x === value) {
            return;
        }

        // X的值的合法范围0-290之间
        if (value < 0 || value > 290) {
            throw new Error("蛇撞墙了！");
        }

        // 修改x时，是在修改水平坐标，蛇在左右移动，蛇在向左移动时，不能向右掉头，反之亦然
        if (this.body[1] && Utils.getX(this.body[1] as HTMLElement) === value) {
            // 如果发生了掉头，让蛇向反方向继续移动
            if (value > this.x) {
                value = this.x - 10;
            } else {
                value = this.x + 10;
            }
        }

        // 移动
        this.moveBody();
        Utils.setX(this.head, value);
        this.checkHeadBody();
    }

    get y() {
        return Utils.getY(this.head);
    }

    set y(value) {
        // 如果新值和旧值相同，则直接返回不再修改
        if (this.y === value) {
            return;
        }

        // Y的值的合法范围0-290之间
        if (value < 0 || value > 290) {
            throw new Error("蛇撞墙了！");
        }

        // 修改y时，是在修改垂直坐标，蛇在上下移动，蛇在向下移动时，不能向上掉头，反之亦然
        if (this.body[1] && Utils.getY(this.body[1] as HTMLElement) === value) {
            // 如果发生了掉头，让蛇向反方向继续移动
            if (value > this.y) {
                value = this.y - 10;
            } else {
                value = this.y + 10;
            }
        }

        // 移动
        this.moveBody();
        Utils.setY(this.head, value);
        this.checkHeadBody();
    }

    /**
     * 获取body的所有坐标组
     */
    get xYs(): number[][] {
        let res: number[][] = [];
        for (const ele of this.body) {
            res.push([Utils.getX(ele as HTMLElement), Utils.getY(ele as HTMLElement)])
        }
        return res;
    }

    /**
     * 蛇身体移动的方法
     */
    moveBody() {
        for (let i = this.body.length - 1; i > 0; i--) {
            let x = Utils.getX(this.body[i - 1] as HTMLElement);
            let y = Utils.getY(this.body[i - 1] as HTMLElement);
            Utils.setX(this.body[i] as HTMLElement, x);
            Utils.setY(this.body[i] as HTMLElement, y);
        }
    }

    addBody() {
        this.element.insertAdjacentHTML("beforeend", "<div></div>");
    }

    /**
     * 检查有没有撞到自己
     */
    checkHeadBody() {
        for (let i = 1; i < this.body.length; i++) {
            if (Utils.getX(this.body[i] as HTMLElement) === this.x
                && Utils.getY(this.body[i] as HTMLElement) === this.y) {
                throw new Error("撞到自己了");
            }
        }
    }
}

export default Snake;